Skip to content

Conversation

@pmikolajczyk41
Copy link
Member

  1. Move the receiver side of the protocol from jit to validation crate.
  2. Make it more generic (work over Read and Write traits, rather than concrete types).
  3. Add the sender side implementation.
  4. Add tests.

Note: the API is synchronous. We don't need async ops at the moment.


closes NIT-4364

@github-actions
Copy link
Contributor

github-actions bot commented Jan 27, 2026

❌ 4 Tests Failed:

Tests completed Failed Passed Skipped
4098 4 4094 0
View the top 3 failed tests by shortest run time
TestPrimaryToSecondaryFailover
Stack Traces | 5.430s run time
=== RUN   TestPrimaryToSecondaryFailover
=== PAUSE TestPrimaryToSecondaryFailover
=== CONT  TestPrimaryToSecondaryFailover
INFO [01-29|08:04:27.044] arbitrum websocket broadcast server is listening address=[::]:46433
    broadcastclients_test.go:206: Primary broadcaster listening on: [::]:46433
INFO [01-29|08:04:27.045] arbitrum websocket broadcast server is listening address=[::]:37687
    broadcastclients_test.go:207: Secondary broadcaster listening on: [::]:37687
    broadcastclients_test.go:230: Primary URL: ws://127.0.0.1:46433
    broadcastclients_test.go:231: Secondary URL: ws://127.0.0.1:37687
INFO [01-29|08:04:27.049] connecting to arbitrum inbox message broadcaster url=ws://127.0.0.1:46433
INFO [01-29|08:04:27.049] arbitrum websocket broadcast server is listening address=[::]:41195
    broadcastclients_test.go:278: Phase 1: Sending messages from primary broadcaster
INFO [01-29|08:04:27.051] connecting to arbitrum inbox message broadcaster url=ws://127.0.0.1:41195
INFO [01-29|08:04:27.051] Feed connected                           feedServerVersion=2 chainId=1234 requestedSeqNum=0
INFO [01-29|08:04:27.059] Feed connected                           feedServerVersion=2 chainId=1234 requestedSeqNum=0
    broadcastclients_test.go:308: Timed out waiting for message 5/5 from primary
--- FAIL: TestPrimaryToSecondaryFailover (5.43s)
TestVersion30
Stack Traces | 7.870s run time
... [CONTENT TRUNCATED: Keeping last 20 lines]
        	/opt/hostedtoolcache/go/1.25.6/x64/src/runtime/debug/stack.go:26 +0x5e
        github.com/offchainlabs/nitro/util/testhelpers.RequireImpl({0x409df70, 0xc04f3be700}, {0x405abc0, 0xc13e607c80}, {0x0, 0x0, 0x0})
        	/home/runner/work/nitro/nitro/util/testhelpers/testhelpers.go:29 +0x55
        github.com/offchainlabs/nitro/system_tests.Require(0xc04f3be700, {0x405abc0, 0xc13e607c80}, {0x0, 0x0, 0x0})
        	/home/runner/work/nitro/nitro/system_tests/common_test.go:2049 +0x5d
        github.com/offchainlabs/nitro/system_tests.testPrecompiles(0xc04f3be700, 0x1e, {0xc12808ddb0, 0x6, 0xc0a23e8820?})
        	/home/runner/work/nitro/nitro/system_tests/precompile_inclusion_test.go:94 +0x371
        github.com/offchainlabs/nitro/system_tests.TestVersion30(0xc04f3be700?)
        	/home/runner/work/nitro/nitro/system_tests/precompile_inclusion_test.go:67 +0x798
        testing.tRunner(0xc04f3be700, 0x3cdb758)
        	/opt/hostedtoolcache/go/1.25.6/x64/src/testing/testing.go:1934 +0xea
        created by testing.(*T).Run in goroutine 1
        	/opt/hostedtoolcache/go/1.25.6/x64/src/testing/testing.go:1997 +0x465
        
    precompile_inclusion_test.go:94: �[31;1m [] execution aborted (timeout = 5s) �[0;0m
INFO [01-29|08:18:04.574] Stopping work on payload                 id=0x03820cc82294c23d reason=delivery
INFO [01-29|08:18:04.575] Imported new potential chain segment     number=6   hash=82a246..4f9b2b blocks=1   txs=1   mgas=2.421  elapsed=1.244ms      mgasps=1944.664 triediffs=18.29KiB   triedirty=0.00B
INFO [01-29|08:18:04.581] Chain head was updated                   number=6   hash=82a246..4f9b2b root=1e3a22..42bda8 elapsed="299.368µs"
WARN [01-29|08:18:04.582] Served eth_call                          reqid=11    duration=7.880481552s  err="execution aborted (timeout = 5s)"
--- FAIL: TestVersion30 (7.87s)
TestVersion40
Stack Traces | 8.150s run time
... [CONTENT TRUNCATED: Keeping last 20 lines]
INFO [01-29|08:18:04.714] Persisted trie from memory database      nodes=23   flushnodes=0 size=3.61KiB   flushsize=0.00B time="131.164µs"  flushtime=0s gcnodes=0 gcsize=0.00B gctime="1.314µs"   livenodes=0    livesize=0.00B
INFO [01-29|08:18:04.714] Writing cached state to disk             block=1   hash=516067..122438 root=d45d64..4e7811
INFO [01-29|08:18:04.714] Persisted trie from memory database      nodes=0    flushnodes=0 size=0.00B     flushsize=0.00B time=941ns        flushtime=0s gcnodes=0 gcsize=0.00B gctime=0s          livenodes=0    livesize=0.00B
INFO [01-29|08:18:04.715] Writing snapshot state to disk           root=28fb26..40a768
INFO [01-29|08:18:04.715] Persisted trie from memory database      nodes=0    flushnodes=0 size=0.00B     flushsize=0.00B time=421ns        flushtime=0s gcnodes=0 gcsize=0.00B gctime=0s          livenodes=0    livesize=0.00B
INFO [01-29|08:18:04.715] Blockchain stopped
INFO [01-29|08:18:04.712] Updated payload                          id=0x0334e7b6460102a0 number=499 hash=601edb..6ecc4e txs=1   withdrawals=0 gas=21000      fees=0.0021         root=210bc5..2e100a elapsed=361.308ms
INFO [01-29|08:18:04.712] Imported new potential chain segment     number=425 hash=a67ae1..3af63c blocks=1   txs=1   mgas=0.161  elapsed=9.107ms      mgasps=17.680   triediffs=1.38MiB    triedirty=311.15KiB
INFO [01-29|08:18:04.716] Chain head was updated                   number=425 hash=a67ae1..3af63c root=5f4b5d..1ab09f elapsed="115.034µs"
INFO [01-29|08:18:04.716] Stopping work on payload                 id=0x0334e7b6460102a0 reason=delivery
INFO [01-29|08:18:04.712] Writing cached state to disk             block=2   hash=66b24f..33dedb root=d4377c..19ca93
INFO [01-29|08:18:04.717] Persisted trie from memory database      nodes=40   flushnodes=0 size=5.45KiB   flushsize=0.00B time="258.172µs"  flushtime=0s gcnodes=0 gcsize=0.00B gctime=0s          livenodes=16   livesize=2.80KiB
INFO [01-29|08:18:04.717] Writing cached state to disk             block=1   hash=532120..9176c4 root=644bc4..7fc062
INFO [01-29|08:18:04.717] Persisted trie from memory database      nodes=16   flushnodes=0 size=2.80KiB   flushsize=0.00B time="71.533µs"   flushtime=0s gcnodes=0 gcsize=0.00B gctime=0s          livenodes=0    livesize=0.00B
INFO [01-29|08:18:04.717] Writing cached state to disk             block=1   hash=532120..9176c4 root=644bc4..7fc062
INFO [01-29|08:18:04.717] Persisted trie from memory database      nodes=0    flushnodes=0 size=0.00B     flushsize=0.00B time="14.818µs"   flushtime=0s gcnodes=0 gcsize=0.00B gctime=0s          livenodes=0    livesize=0.00B
INFO [01-29|08:18:04.717] Writing snapshot state to disk           root=4ea197..8303c6
INFO [01-29|08:18:04.717] Persisted trie from memory database      nodes=0    flushnodes=0 size=0.00B     flushsize=0.00B time="6.512µs"    flushtime=0s gcnodes=0 gcsize=0.00B gctime=0s          livenodes=0    livesize=0.00B
INFO [01-29|08:18:04.717] Blockchain stopped
--- FAIL: TestVersion40 (8.15s)

📣 Thoughts on this report? Let Codecov know! | Powered by Codecov

@codecov
Copy link

codecov bot commented Jan 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 32.64%. Comparing base (178383c) to head (5d50e38).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4280      +/-   ##
==========================================
- Coverage   34.42%   32.64%   -1.78%     
==========================================
  Files         482      482              
  Lines       57031    57031              
==========================================
- Hits        19631    18619    -1012     
- Misses      33911    35178    +1267     
+ Partials     3489     3234     -255     

Copy link
Contributor

@bragaigor bragaigor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good and seems that most of my comments are nitpicks :)

@@ -0,0 +1,3 @@
### Ignored
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Ignored
### Internal

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that we added this section, thanks! fixed in eab1044

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is that the ones introduced in #4269 to be substituted for these ones right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exactly - actually, I was partly basing this PR on your code

Comment on lines +293 to 296
if input.has_delayed_msg {
env.delayed_messages
.insert(input.delayed_msg_nr, input.delayed_msg);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will there always be just one delayed_message? Asking because before, just like sequencer_messages, delayed_messages was wrapped in a while loop

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

citing Tsahi:

Currently - it can only contain a single delayed message. There are future thoughs about having multiple delayed messages in a single block but that'll only happen after MEL and we could tackle it then.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so there's some lack of consistency in the code, but right now I tried to persist the existing behavior and data structs

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah got it, thanks!

let hash = socket::read_bytes32(stream)?;
let preimage = socket::read_bytes(stream)?;
for (preimage_type, preimages) in input.preimages {
let map = env.preimages.entry(preimage_type).or_default();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: map is a bit too generic and I know it was already there, maybe we could rename to something like preimage_map? Up to you

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed in 043c73f

batch_info: inbox,
delayed_msg: delayed_message.data,
start_state,
user_wasms: HashMap::from([(local_target(), user_wasms)]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why having a HashMap instead of just user_wasms?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because ValidationInput has HashMap here, in case someone wants to pass wasms for multiple different archs

Comment on lines 12 to 18
pub type IOResult<T> = Result<T, io::Error>;

const SUCCESS: u8 = 0x0;
const FAILURE: u8 = 0x1;
// const PREIMAGE: u8 = 0x2; // legacy, not used
const ANOTHER: u8 = 0x3;
const READY: u8 = 0x4;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: I don't have a strong opinion but maybe these could go into their own file constants.rs? and keep mod.rs with just the mods?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to markers.rs to make it more explicit what constants they are

Comment on lines 106 to 113
if self.has_delayed_msg {
Some(BatchInfo {
number: self.delayed_msg_nr,
data: self.delayed_msg.clone(),
})
} else {
None
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick suggestion

Suggested change
if self.has_delayed_msg {
Some(BatchInfo {
number: self.delayed_msg_nr,
data: self.delayed_msg.clone(),
})
} else {
None
}
self.has_delayed_msg.then(|| BatchInfo {
number: self.delayed_msg_nr,
data: self.delayed_msg.clone(),
})

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Comment on lines 16 to 23
pub fn local_target() -> String {
match (env::consts::OS, env::consts::ARCH) {
("linux", "aarch64") => "arm64",
("linux", "x86_64") => "amd64",
_ => "host",
}
.to_string()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick suggestion coming from #4269

Suggested change
pub fn local_target() -> String {
match (env::consts::OS, env::consts::ARCH) {
("linux", "aarch64") => "arm64",
("linux", "x86_64") => "amd64",
_ => "host",
}
.to_string()
}
pub fn local_target() -> &'static str {
if cfg!(all(target_os = "linux", target_arch = "aarch64")) {
TARGET_ARM_64
} else if cfg!(all(target_os = "linux", target_arch = "x86_64")) {
TARGET_AMD_64
} else {
TARGET_HOST
}
}

then the const can go into the contstants.rs file if you decide to create one:

pub(crate) const TARGET_ARM_64: &str = "arm64";
pub(crate) const TARGET_AMD_64: &str = "amd64";
pub(crate) const TARGET_HOST: &str = "host";

Again up to you

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applied suggestion ✅

use std::io::ErrorKind::InvalidData;
use std::io::{Error, Write};

pub fn send_validation_input(writer: &mut impl Write, input: &ValidationInput) -> IOResult<()> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems like this and send_batches, send_preimages, and send_user_wasms are only used in tests? Unless I missed their caller? If so, wouldn't it be best to move them down to the test file itself? Or we have plans to use them in the future somewhere?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hopefully all these will be used in your continuous mode (replacing existing inlined protocol) :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, that would simplify things

@pmikolajczyk41 pmikolajczyk41 removed their assignment Jan 28, 2026
Copy link
Contributor

@bragaigor bragaigor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@bragaigor bragaigor assigned eljobe and unassigned bragaigor Jan 28, 2026
@eljobe eljobe added this pull request to the merge queue Jan 29, 2026
Any commits made after this event will not be merged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants